package orm

import (
	"context"
	"my_framework/orm/internal/errs"
	"my_framework/orm/model"
	"reflect"
	"strings"
)

type OnDuplicateKeyBuilder[T any] struct {
	i               *Inserter[T]
	conflictColumns []string
}

type OnDuplicateKey struct {
	assigns         []Assignable
	conflictColumns []string
}

type Assignable interface {
	assign()
}

type Inserter[T any] struct {
	builder
	values  []*T
	db      *DB
	columns []string
	//onDuplicateKey []Assignable
	onDuplicateKey *OnDuplicateKey
}

//func (i *Inserter[T]) OnDuplicateKey(assigns ...Assignable) *Inserter[T] {
//	i.onDuplicateKey = assigns
//	return i
//}

// ConflictColumns 中间方法
func (o *OnDuplicateKeyBuilder[T]) ConflictColumns(cols ...string) *OnDuplicateKeyBuilder[T] {
	o.conflictColumns = cols
	return o
}

func (o *OnDuplicateKeyBuilder[T]) Update(assigns ...Assignable) *Inserter[T] {
	o.i.onDuplicateKey = &OnDuplicateKey{
		assigns:         assigns,
		conflictColumns: o.conflictColumns,
	}
	return o.i
}

func (i *Inserter[T]) OnDuplicateKey() *OnDuplicateKeyBuilder[T] {
	return &OnDuplicateKeyBuilder[T]{
		i: i,
	}
}

func NewInserter[T any](db *DB) *Inserter[T] {
	return &Inserter[T]{
		builder: builder{
			dialect: db.dialect,
			quoter:  db.dialect.quoter(),
			sb:      &strings.Builder{},
		},
		db: db,
	}
}

func (i *Inserter[T]) Values(vals ...*T) *Inserter[T] {
	i.values = vals
	return i
}

func (i *Inserter[T]) Columns(cols ...string) *Inserter[T] {
	i.columns = cols
	return i
}

func (i *Inserter[T]) Build() (*Query, error) {
	if len(i.values) == 0 {
		return nil, errs.ErrInsertZeroRow
	}
	//var sb strings.Builder
	i.sb.WriteString("INSERT INTO ")
	// 拿到元数据
	var err error
	i.model, err = i.db.r.Get(i.values[0])
	if err != nil {
		return nil, err
	}
	// 拼接表名
	//sb.WriteByte('`')
	//sb.WriteString(m.TableName)
	//sb.WriteByte('`')
	i.quote(i.model.TableName)
	// 显示地指定列的顺序,不然很难处理
	i.sb.WriteByte('(')

	fields := i.model.Fields
	// 用户指定了列
	if len(i.columns) > 0 {
		fields = make([]*model.Field, 0, len(i.columns))
		for _, fd := range i.columns {
			fdMeta, ok := i.model.FieldMap[fd]
			// 传入错误的列
			if !ok {
				return nil, errs.NewErrUnknownField(fd)
			}
			fields = append(fields, fdMeta)
		}
	}

	// 遍历map的顺序是随机的,不能遍历fieldmap或colmap拼接(x,x,x,x)
	for idx, field := range fields {
		if idx > 0 {
			i.sb.WriteByte(',')
		}
		//i.sb.WriteByte('`')
		//i.sb.WriteString(field.ColName)
		//i.sb.WriteByte('`')
		i.quote(field.ColName)
	}
	i.sb.WriteByte(')')

	i.sb.WriteString(" VALUES ")
	//sb.WriteByte('(')
	i.args = make([]any, 0, len(i.values)*len(fields))
	for j, val := range i.values {
		if j > 0 {
			i.sb.WriteByte(',')
		}
		i.sb.WriteByte('(')

		for idx, field := range fields {
			if idx > 0 {
				i.sb.WriteByte(',')
			}
			i.sb.WriteByte('?')
			// 读取参数
			arg := reflect.ValueOf(val).Elem().
				FieldByName(field.GoName).Interface()
			//args = append(args, arg)
			i.addArg(arg)
		}
		i.sb.WriteByte(')')
	}

	// on duplicate
	if i.onDuplicateKey != nil {
		err = i.dialect.buildOnDuplicateKey(&i.builder, i.onDuplicateKey)
		if err != nil {
			return nil, err
		}
	}

	i.sb.WriteByte(';')

	return &Query{
		SQL:  i.sb.String(),
		Args: i.args,
	}, err
}

func (i *Inserter[T]) BuildUnsafe() (*Query, error) {
	if len(i.values) == 0 {
		return nil, errs.ErrInsertZeroRow
	}
	//var sb strings.Builder
	i.sb.WriteString("INSERT INTO ")
	// 拿到元数据
	var err error
	i.model, err = i.db.r.Get(i.values[0])
	if err != nil {
		return nil, err
	}
	// 拼接表名
	//sb.WriteByte('`')
	//sb.WriteString(m.TableName)
	//sb.WriteByte('`')
	i.quote(i.model.TableName)
	// 显示地指定列的顺序,不然很难处理
	i.sb.WriteByte('(')

	fields := i.model.Fields
	// 用户指定了列
	if len(i.columns) > 0 {
		fields = make([]*model.Field, 0, len(i.columns))
		for _, fd := range i.columns {
			fdMeta, ok := i.model.FieldMap[fd]
			// 传入错误的列
			if !ok {
				return nil, errs.NewErrUnknownField(fd)
			}
			fields = append(fields, fdMeta)
		}
	}

	// 遍历map的顺序是随机的,不能遍历fieldmap或colmap拼接(x,x,x,x)
	for idx, field := range fields {
		if idx > 0 {
			i.sb.WriteByte(',')
		}
		//i.sb.WriteByte('`')
		//i.sb.WriteString(field.ColName)
		//i.sb.WriteByte('`')
		i.quote(field.ColName)
	}
	i.sb.WriteByte(')')

	i.sb.WriteString(" VALUES ")
	//sb.WriteByte('(')
	i.args = make([]any, 0, len(i.values)*len(fields))
	for j, val := range i.values {
		if j > 0 {
			i.sb.WriteByte(',')
		}
		i.sb.WriteByte('(')

		v := i.db.creator(i.model, val)

		for idx, field := range fields {
			if idx > 0 {
				i.sb.WriteByte(',')
			}
			i.sb.WriteByte('?')
			// 读取参数
			arg, err := v.Filed(field.GoName)
			if err != nil {
				return nil, err
			}
			//args = append(args, arg)
			i.addArg(arg)
		}
		i.sb.WriteByte(')')
	}

	// on duplicate
	if i.onDuplicateKey != nil {
		err = i.dialect.buildOnDuplicateKey(&i.builder, i.onDuplicateKey)
		if err != nil {
			return nil, err
		}
	}

	i.sb.WriteByte(';')

	return &Query{
		SQL:  i.sb.String(),
		Args: i.args,
	}, err
}

func (i *Inserter[T]) Exec(ctx context.Context) Result {
	q, err := i.Build()
	if err != nil {
		return Result{
			err: err,
		}
	}
	res, err := i.db.db.Exec(q.SQL, q.Args...)
	return Result{
		err: err, res: res,
	}
}
